#include "levelbeginstate.h"
#include "levelstate.h"

void LevelBeginState::ServerInit()
{
	m_work_manager = m_server->work_manager();
	m_guid = m_server->GetGUID();

	m_wait_for_ready_timer = al_create_timer(1.0f);
	al_start_timer(m_wait_for_ready_timer);
}

void LevelBeginState::ServerCleanup()
{
	if (m_shutdown_network_on_state_end)
	{
		m_server->Shutdown();
		delete m_server;
	}

	al_destroy_timer(m_wait_for_ready_timer);
}

void LevelBeginState::DoServerWork()
{
	Job next_job;
	while (m_work_manager->GetJobToLocal(next_job))
	{
		unsigned char type_id;
		next_job.data->Read(type_id);
		switch (type_id)
		{
			// TODO: Handle new connection. We can just kick them or send a special message that the game has already
			// started or we can even tell the server to not allow any more connections.
		case ID_DISCONNECTION_NOTIFICATION:
		case ID_CONNECTION_LOST:
			ServerRemovePlayer(next_job.sender_guid);
			break;

		case ID_CLIENT_READY:
			ServerProcessClientReady(next_job);
			break;
		};

		next_job.JobDone();
	}
}

void LevelBeginState::ServerRemovePlayer(std::string guid)
{
	// Remove the client.
	m_client_list.RemoveClient(guid);

	// Tell everyone that the client removed is not there anymore.				
	Job job(ID_REMOVE_CLIENT);
	RakNet::StringCompressor::Instance()->EncodeString(RakNet::RakString(guid.c_str()), 64, job.data);

	job.broadcast = true;
	m_work_manager->JobToRemote(job);
}

void LevelBeginState::ServerKickPlayer(std::string guid)
{
	// Close the connection. This will automatically trigger an ID_DISCONNECTION_NOTIFICATION which will then
	// trigger the ServerRemovePlayer command below.
	m_server->CloseConnection(guid);
}

void LevelBeginState::ServerProcessClientReady(Job client_ready_job)
{
	// First we check whether the client already exists in case we got the message more than one time.
	for (std::list<std::string>::iterator it = m_clients_ready.begin(); it != m_clients_ready.end(); it++)
		if ((*it) == client_ready_job.sender_guid)
			return;

	m_clients_ready.push_back(client_ready_job.sender_guid);
}

void LevelBeginState::ServerStartLevel()
{
	m_shutdown_network_on_state_end = false;

	Job job(ID_STARTLEVEL);
	job.broadcast = true;
	m_work_manager->JobToRemote(job);

	LevelState* next_state = new LevelState(m_engine);
	next_state->Init(m_is_server, m_server, m_client, m_client_list, m_level);
	m_engine->SetNextState(next_state);
}

void LevelBeginState::ServerUpdate()
{
	DoServerWork();

	if (!m_ready_signal_sent && al_get_timer_count(m_fade_out_timer) > 100)
	{
		m_ready_signal_sent = true;
		m_clients_ready.push_back(m_guid);
	}

	// Check who is ready.
	bool everyone_ready = true;
	for (unsigned i = 0; i < m_client_list.GetSize(); i++)
	{
		ClientConnection client;
		if (m_client_list.GetClient(i, client))
		{
			// If the guid is not registered as ready.
			if (std::find(m_clients_ready.begin(), m_clients_ready.end(), client.guid()) == m_clients_ready.end())
			{
				// If we have waited for too long, we just don't wait any more and start.
				if(al_get_timer_count(m_wait_for_ready_timer) <= 120)
				{
					everyone_ready = false;
					break;
				}
			}
		}
	}

	if (everyone_ready)
	{
		ServerStartLevel();
	}
}